package gdlDao.framework.aop;

import gdl.test.bean.User;
import gdlDao.framework.annotation.GdlSQL;
import gdlDao.framework.dao.IGdlSupportDao;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.jdbc.core.simple.ParameterizedBeanPropertyRowMapper;

public class GdlDaoHandler implements MethodInterceptor {
	
	private IGdlSupportDao gdlSupportDao;
	private JdbcTemplate jdbcTemplate;

	@SuppressWarnings({ "rawtypes", "unchecked" })
	@Override
	public Object invoke(MethodInvocation methodInvocation) throws Throwable {
		Method method = methodInvocation.getMethod();
		Object[] args = methodInvocation.getArguments();
		
		if (!isAbstract(method)) {
            return methodInvocation.proceed();
		}
		
		if(gdlDaoHiber(method, args)){
			return null;
		}
		
		if(method.isAnnotationPresent(GdlSQL.class)){
			GdlSQL ms=(GdlSQL)method.getAnnotation(GdlSQL.class);
			String sql=ms.sql();
			Class<?> returnType = method.getReturnType();
			
			if(returnType.isAssignableFrom(List.class)){
				Class<?> returnClass=Class.forName(ms.entityClass());
				return jdbcTemplate.query(sql, args, ParameterizedBeanPropertyRowMapper.newInstance(returnClass));
			}else{
				/*RowMapper<?> rm = ParameterizedBeanPropertyRowMapper.newInstance(returnType);
				return jdbcTemplate.queryForObject(sql,args,rm );*/
				//RowMapper<?> rm = ParameterizedBeanPropertyRowMapper.newInstance(returnType);
				return jdbcTemplate.queryForObject(sql,args,returnType );
			}
			
			// 判断returnType对象是否是一个基本类型（boolean、byte、char、short、int、long、float、double和void）
			/*if (returnType.isPrimitive()) {
				RowMapper<?> rm = ParameterizedBeanPropertyRowMapper.newInstance(returnType);
				return jdbcTemplate.queryForObject(sql,args,rm );
				Number number = jdbcTemplate.queryForObject(sql,args,BigDecimal.class);
				if ("int".equals(returnType.toString())) {
					return number.intValue();
				} else if ("long".equals(returnType.toString())) {
					return number.longValue();
				} else if ("double".equals(returnType.toString())) {
					return number.doubleValue();
				}
			}
			else if(returnType.isAssignableFrom(List.class)){
				//return jdbcTemplate.queryForList(sql,args);
				//String[] values = returnType.get;
				Class<?> returnClass=Class.forName(ms.entityClass());
				return jdbcTemplate.query(sql, args, ParameterizedBeanPropertyRowMapper.newInstance(returnClass));
				
				Class<?> returnClass=Class.forName(ms.entityClass());
				List<Map<String, Object>> list=jdbcTemplate.queryForList(sql,args);
				List res=new ArrayList();
				for(int i=0;i<list.size();i++){
					Map<String,Object> map=list.get(i);
					res.add(convertMap(returnClass, map));
				}
				return res;
			}
			else if(returnType.isAssignableFrom(String.class)){
				return jdbcTemplate.queryForObject(sql,args, String.class);
			}else{
				try{
					RowMapper<?> rm = ParameterizedBeanPropertyRowMapper.newInstance(returnType);
					return jdbcTemplate.queryForObject(sql,args,rm );
				}catch(Exception e){
					e.printStackTrace();
				}
			}*/
			
		}
		return null;
	}
	
	private boolean gdlDaoHiber(Method method,Object[] args){
		
		if(method.getName().equals("add")){
			gdlSupportDao.add(args[0]);
			return true;
		}
		if(method.getName().equals("delete")){
			gdlSupportDao.delete(args[0]);
			return true;
		}
		if(method.getName().equals("update")){
			gdlSupportDao.update(args[0]);
			return true;
		}
		return false;
	}
	
	public JdbcTemplate getJdbcTemplate() {
		return jdbcTemplate;
	}

	public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
		this.jdbcTemplate = jdbcTemplate;
	}

	public IGdlSupportDao getGdlSupportDao() {
		return gdlSupportDao;
	}

	public void setGdlSupportDao(IGdlSupportDao gdlSupportDao) {
		this.gdlSupportDao = gdlSupportDao;
	}
	
	public static boolean isAbstract(Method method) {
		int mod = method.getModifiers();
		return Modifier.isAbstract(mod);
	}
	
	@SuppressWarnings("rawtypes")
	public static Object convertMap(Class type, Map<String,Object> map)
            throws IntrospectionException, IllegalAccessException,
            InstantiationException, InvocationTargetException {
        BeanInfo beanInfo = Introspector.getBeanInfo(type); // 获取类属性
        Object obj = type.newInstance(); // 创建 JavaBean 对象

        // 给 JavaBean 对象的属性赋值
        PropertyDescriptor[] propertyDescriptors =  beanInfo.getPropertyDescriptors();
        for (int i = 0; i< propertyDescriptors.length; i++) {
            PropertyDescriptor descriptor = propertyDescriptors[i];
            String propertyName = descriptor.getName();

            if (map.containsKey(propertyName)) {
                // 下面一句可以 try 起来，这样当一个属性赋值失败的时候就不会影响其他属性赋值。
                Object value = map.get(propertyName);

                Object[] args = new Object[1];
                args[0] = value;

                descriptor.getWriteMethod().invoke(obj, args);
            }
        }
        return obj;
	}
	public static void main(String[] args) throws Exception {
		List<User> list = new ArrayList<User>();
		Class<?> cls = list.getClass();
		
		Method method = list.getClass().getMethod("get",null); 
		Class returnTypeClass = method.getReturnType();
		System.out.println(returnTypeClass);
				
		ParameterizedType pt = (ParameterizedType) cls.getField(  
				"list").getGenericType();  
		System.out.println(pt.getActualTypeArguments().length);  
		System.out.println(pt.getActualTypeArguments()[0]); 
		System.out.println(cls);
	}
}
